#ifndef _AST_H
#define _AST_H

#include <stdbool.h>

struct translateunit;
struct i_list;
struct e_element;
struct e_elemlist;
struct e_enumerate;
struct e_list;
struct v_variable;
struct v_list;
struct f_function;
struct f_list;
struct s_statement;
struct s_list;
struct t_type;
struct x_expression;
struct x_list;
struct p_position;

/* Translation Unit */

struct translationunit {
	struct e_list *e;
	struct v_list *v;
	struct f_list *f;
};

/* Identifier */

struct i_list {
	int count;

	struct i_node {
		char *identifier;
		struct i_node *next;
	} *first;
};

/* Enumerate */

struct e_element {
	char *identifier;
	int value;
	int sequence;
	char *desc;
};

struct e_elemlist {
	int count;

	struct e_elemnode {
		struct e_element *element;
		struct e_elemnode *next;
	} *first;
};

enum e_cate {
	E_BASE,
	E_COMB
};

struct e_enumerate {
	char *identifier;
	enum e_cate cate;

	union {
		struct {
			struct e_elemlist *elemlist;
		} base;

		struct {
			struct i_list *identifiers;
		} comb;
	} spec;
};

struct e_list {
	int count;

	struct e_node {
		struct e_enumerate *enumerate;
		struct e_node *next;
	} *first;
};

/* Variable */

struct v_variable {
	char *identifier;
	struct t_type *type;
};

struct v_list {
	int count;

	struct v_node {
		struct v_variable *variable;
		struct v_node *next;
	} *first;
};

/* Function */

enum f_cate {
	F_FUNCTION,
	F_EVENT
};

struct f_function {
	enum f_cate cate;

	char *identifier;
	struct v_list *variables;
	struct s_list *statements;

	union {
		struct {
			struct t_type *returntype;
			struct v_list *arguments;
		} function;
	} spec;
};

struct f_list {
	int count;

	struct f_node {
		struct f_function *function;
		struct f_node *next;
	} *first;
};

/* Statement */

enum s_cate {
	S_EXPRESSION,
	S_IF,
	S_IF_ELSE,
	S_WHILE,
	S_DO_WHILE,
	S_FOR,
	S_BREAK,
	S_CONTINUE,
	S_RETURN,
	S_CALL,
	S_TRANS,
	S_INPUT,
	S_OUTPUT
};

struct s_statement {
	enum s_cate cate;

	union {
		struct {
			struct x_expression *expression;
		} expression;

		struct {
			struct x_expression *condition;
			struct s_list *statements;
		} s_if;

		struct {
			struct x_expression *condition;
			struct s_list *truestatements;
			struct s_list *falsestatements;
		} s_if_else;

		struct {
			struct x_expression *condition;
			struct s_list *statements;
		} s_while;

		struct {
			struct x_expression *condition;
			struct s_list *statements;
		} s_do_while;

		struct {
			struct x_expression *initialization;
			struct x_expression *condition;
			struct x_expression *iteration;
			struct s_list *statements;
		} s_for;

		struct {
			struct x_expression *value;
		} s_return;

		struct {
			char *eventidentifier;
		} s_call;

		struct {
			char *eventidentifier;
		} s_trans;

		struct {
			struct x_expression *screen;
			struct x_expression *destination;
		} s_input;

		struct {
			struct x_expression *screen;
			char *string;
		} s_output;
	} spec;
};

struct s_list {
	int count;

	struct s_node {
		struct s_statement *statement;
		struct s_node *next;
	} *first;
};

/* Type Expression */

enum t_cate {
	T_INTEGER,
	T_BOOLEAN,
	T_ENUMERATE,
	T_ARRAY_INT,	// Derivated
	T_ARRAY_ENUM,	// Derivated
	T_CONTAINER	// Derivated
};

struct t_type {
	enum t_cate cate;

	union {
		struct {
			char *identifier;
		} enumerate;

		struct {
			struct t_type *elemtype;
			struct x_expression *size;
		} array_int;

		struct {
			struct t_type *elemtype;
			char *enumerate;
		} array_enum;

		struct {
			struct t_type *elemtype;
		} container;
	} spec;

	int refcount;
};

/* Expression */

enum x_cate {
	X_UNARY,
	X_BINARY,
	X_TRINARY,
	X_IDENTIFIER,
	X_INTEGER,
	X_BOOLEAN,
	X_CALL,
	X_ARRAY,
	X_DS
};

enum x_unop {
	X_NOT,

	X_LINC,
	X_LDEC,
	X_LSUB,

	X_RINC,
	X_RDEC,
};

enum x_binop {
	X_ASSIGN,

	X_OR,
	X_AND,

	X_EQ,
	X_NE,
	X_LT,
	X_LE,
	X_GT,
	X_GE,

	X_ADD,
	X_SUB,
	X_MUL,
	X_DIV,
	X_MOD,
};

enum x_triop {
	X_COND,
};

enum x_dsop {
	X_RANDOM,
	X_VALUE,
	X_SIZE,
	X_FILL,
	X_SHUFFLE,
	X_PEEK,
	X_REMOVE,
	X_INSERT,
	X_EXTRACT,
	X_COMBINE
};

struct x_list {
	int count;

	struct x_node {
		struct x_expression *expression;
		struct x_node *next;
	} *first;
};

struct x_expression {
	enum x_cate cate;

	union {
		struct {
			enum x_unop oper;
			struct x_expression *opnd;
		} unary;

		struct {
			enum x_binop oper;
			struct x_expression *left;
			struct x_expression *right;
		} binary;

		struct {
			enum x_triop oper;
			struct x_expression *first;
			struct x_expression *second;
			struct x_expression *third;
		} trinary;

		struct {
			char *identifier;
		} identifier;

		struct {
			int integer;
		} integer;

		struct {
			bool boolean;
		} boolean;

		struct {
			char *function;
			struct x_list *arguments;
		} call;

		struct {
			char *array;
			struct x_expression *index;
		} array;

		struct {
			enum x_dsop oper;

			union {
				struct {
					struct t_type *type;
				} random;

				struct {
					struct x_expression *enumerate;
				} value;

				struct {
					struct x_expression *container;
				} size, fill, shuffle;

				struct {
					struct x_expression *container;
					struct p_position *position;
				} peek, remove;

				struct {
					struct x_expression *container;
					struct p_position *position;
					struct x_expression *element;
				} insert;

				struct {
					struct x_expression *enumerate;
					struct x_expression *index;
				} extract;

				struct {
					struct x_list *components;
				} combine;
			} spec;
		} ds;
	} spec;
};

/* Position */

enum p_cate {
	P_TOP,
	P_BOTTOM,
	P_RANDOM,
	P_EXPRESSION
};

struct p_position {
	enum p_cate cate;

	union {
		struct {
			struct x_expression *expression;
		} expression;
	} spec;
};

#endif
